GenDS: Dosadi Generic TWAIN DataSource
Developer Notes

 

Revision 3, 2001.09.25   BETA VERSION 1.01

 

 

 

 

 

Table of Contents

Table of Contents.. 1

GenDS Overview.. 2

The GenDS Visual C++ Project 2

Platform Support 3

Key TWAIN Concepts. 3

Capabilities. 3

User Interface Mode vs. No-UI Mode. 3

Resolution. 4

Architecture of GenDS. 4

Internationalizing and Localizing GenDS. 4

1. Localized Resource DLLs, Selected at Install 4

2. Localized Resource DLLs, Selected at Run-time. 4

 


 

GenDS Overview

GenDS is a generic Visual C++ framework for a TWAIN DataSource.  A TWAIN DataSource (DS) is a kind of high-level device driver for transferring images from a source (such as a scanner) to an image-consuming application.  The communication between the application and the DS uses the TWAIN API and protocol, an industry standard described by the TWAIN Specification [see www.twain.org/docs for current and past versions.]

In writing GenDS and this document, I have made the following assumption:  You are a developer, assigned or hired by an imaging device manufacturer to implement TWAIN support for a hardware imaging device or family of such devices.  The device might be a scanner, film digitizer, webcam, video capture card, or a digital still camera (DSC) – or it might be some hybrid of several of these.  Your ‘device’ could even be a software-only image database.

GenDS is intended to provide you with a large percentage of the code that is specific to a TWAIN DS, but generic across many devices – it contains the code that “everybody has to write”, so you in theory write just the code that is unique to your DS.  GenDS uses an architecture that is fully competent; that takes into account the many subtleties of the TWAIN API – I’ve already been down the blind alleys for you.  GenDS is designed to prevent or detect many common mistakes and omissions.  In a sense, GenDS is an expert system that embodies and packages my experience over the last 8 years writing and using TWAIN DataSources.

Just to keep my job within some bounds, I also assume that:

1.You have downloaded the TWAIN specification and are studying it, but are not a TWAIN expert.  I apologize in advance for explaining things you already know, and repeating myself in places.

2. You are competent in C++, are familiar with Microsoft Visual C++ and its Integrated Development Environment (IDE) and are reasonably familiar with the main user-interface building parts of MFC.  I don’t assume you are a C++ expert, or that you have carefully read every line of MFC code and documentation.  I know I haven’t.

3. You understand pretty well what your device or devices can do, how to “talk” to them in the sense of writing code to communicate with and control them, and that you understand general raster imaging concepts like pixels, samples, DPI, rows versus columns, analog-to-digital conversion (digitization).

The GenDS Visual C++ Project

GenDS is delivered in the form of a Microsoft Visual C++ 6.0 workspace containing a single project that builds an MFC DLL.  It can be opened from GenDS.dsw, and should build immediately.  As initially configured, it builds a DataSource file named “GenDS.ds”, which will appear in TWAIN applications as a TWAIN device named “Generic DataSource”.

An accompanying document called the Customization Checklist lists the main steps in specializing and customizing GenDS to a particular device or device family.  The remainder of this document addresses specific questions you might have about using GenDS, that are not covered in the Customization Checklist.

Platform Support

The Beta 1 version of GenDS has only been tested on Windows 98 SE (Second Edition).  GenDS is built using only standard Win32 and MFC services, so it should build and operate without problem on Win 98 (first edition), Win 95, Win 2K, and NT 5.0.  Please contact Dosadi immediately if you encounter a problem you suspect could be platform-related: support@dosadi.com

Key TWAIN Concepts

Capabilities

Capabilities are individual settings or device properties that can be communicated between the DS and the application.  You will see this term a lot in the TWAIN documentation, and throughout GenDS.  A capability, often called a ‘cap’, is a parameter of the device that can be set by the application, or a property of the device that can queried by the application.  In a few odd cases, a capability effectively represents an operation the device can perform, such as ejecting a page.

Each capability has a unique integer code, assigned in the TWAIN.H file with an identifier of the form CAP_xxx or ICAP_xxx.  The CAP_ capabilities are meant to not be specific to imaging, and the ICAP’s are specifically related to imaging.  (TWAIN has some intentions of handling other forms of data besides images.)

Examples of capabilities:

ICAP_PIXELTYPE

Specifies the kind of pixels to be acquired – B&W, Grayscale, RGB color, palettized, CMYK, and so on.  TWAIN defines the list of possibilities, but each device chooses which pixel types it offers.

CAP_PAPERDETECTABLE

A Boolean (True or False) property of the DataSource, which can be queried but not set by the application.  If this capability has the value TRUE, it means that the device has a feeder of some kind, and that it can tell if there are documents in the feeder.

 

The capabilities of a GenDS DataSource are stored in an object of class CMySettings, derived from CSettings.  Capabilities have complex values that are stored in objects that TWAIN calls Containers, and GenDS has a corresponding class Container (see container.h).

User Interface Mode vs. No-UI Mode

This is an important TWAIN concept, and the origin of a great deal of bad or frustrating DataSource code.  Every TWAIN DataSource is expected to function in two very different modes:  In the “User Interface” mode, the application specifies as little as possible (“give me some images”) and the DataSource is expected to display a user interface that allows the user to specify whatever needs to be specified.  On a flatbed, for example, the user interface will normally offer choices for resolution, for pixel type (B&W, grayscale, color), area to scan, gamma correction, and so on.  With a Digital Still Camera, the user will need to specify which photos from the camera’s memory are to be transferred to the application.  And so on.  This is the mode used by Adobe Photoshop, Paint Shop Pro, and pretty much every imaging and graphic-arts application.

Then there are those applications that do want to be involved, that want control over the device.  Their motivations vary, but usually include one or more of these:

  1. The image transfer needs to take place without human intervention,
  2. The device user interface is deemed unsuitable for the application’s target audience, or
  3. The application has special requirements that imply more control over the device.

A TWAIN DataSource is required to be able to operate without showing its user interface if so requested by the application.  In actual practice, this has to be relaxed for some devices – for example, the old hand-scanners (does anybody still make those?) required manual, human intervention to operate – the (a) case above is meaningless.[1]  A reasonable engineering approach is to try to satisfy the three application needs listed above to the greatest extent practical with your device.  If your device absolutely requires some user input, then you will have to have a ‘No User-Interface interface’ – but it should be as utterly simple as possible, with all possible control left up to the application, and workable defaults for anything the application does not specify.

Resolution

I hate this one!  Long ago…  when TWAIN was just for scanners… everybody pretty much agreed on the meaning of ‘resolution’ – it meant samples per physical unit of distance, most commonly given in dots per inch or DPI.  With the advent of video capture cards, webcams, and all kinds of digital cameras, the consensus shifted to hold that that these devices did not have resolution in the sense of DPI.  The TWAIN standard has awkwardly and in shrouded language, embraced this latter possibility.  Beginning as early as TWAIN 1.6, for example: “XResolution or YResolution—Set to -1 if the device creates data with no inherent resolution (such as a digital camera).”

There are other places in the TWAIN standard where resolution (or the possible lack of it) comes up in various forms, and it has been confusing for both DataSource and application developers.  My personal concerns are (1) that we don’t crash applications, for example by returning a resolution of 0 which the application then divides by, and (2) that we don’t create nonsensical results for end-users by an overly literal interpretation of the standard – for example by returning images whose print size is 4 x 4 miles, or 30 x 25 mm.

If your device has “no inherent resolution” as the TWAIN spec puts it, or your inherent resolution is unusual e.g. Landsat images at 1 pixel = 12 meters, then here is my (strictly personal) opinion:

Always return a value for resolution that makes your images work well for users in applications that think your device is a flatbed scanner.  If your images are 640 pixels x480 pixels, go ahead and claim that their resolution is 100 or 120 dpi.  This will cause them to be treated as 6.4” x 4.8” or 5.3” x 4” especially when printed, which is quite practical.

If it really bugs you to transmit such fictitious, mathematically and scientifically unjustifiable data (like, if you are Swiss) then set the Native Resolution of your device to 0.  This tells any application that is interested, that your device does not really have any “inherent resolution.”


Architecture of GenDS

GenDS is built on four main objects that cooperate to implement the DS, with several abstract types for support, plus a couple of ‘service’ modules.

 

 

 

 

 

 

 

 

 

 


Each of these ‘big’ objects is a singleton – there is just one at run-time.  Each is based on an underlying generic class: CGenDS, CGenDialog, CGenDevice and CSettings.

CMyDS exports the TWAIN entry point from the DLL, and does the work of parsing and tracking the TWAIN API.  It is the application object (derived from CWinApp), and is the senior object, the one that represents “the DataSource.”

CMySettings: The CMySettings object is in charge of all of your capabilities – it stores their current values, and allows them to be queried and set by the rest of the DS, and by the application through TWAIN.  If you take a look at Settings.h, you will quickly get a sense of what this object does.

CMyDevice represents your device:  This is the object that talks to your hardware, or to your lower-level driver.  It is responsible for querying the state of the device, for relaying settings to the device, and for initiating and coordinating the transfer of images.

CMyDialog:  This is the normal user interface of your DataSource, implemented as a standard MFC modeless dialog.  Unless the application asks for ‘No UI’, this dialog will be displayed when the DS is enabled for scanning.  In the OnInitDialog method, this dialog typically arranges its controls, configures them to display the allowed and current settings, and then lets the user tweak things.  As the user manipulates the dialog controls, the revised settings can be propagated back to the CMySettings object through CMyDialog::m_settings.  When the user is satisfied with the settings, there is typically a ‘Scan’ or ‘Transfer’ button that causes a call to CMyDevice::StartScan to initiate the first image transfer.

Internationalizing and Localizing GenDS

This Beta 1 version of GenDS is not ideally prepared for internationalization, although we have taken the first step: All of the user-interface elements of GenDS, including specifically all user-visible text strings, are in the Resources section – a Release build of GenDS will not contain any American English text embedded in the code.

If you are not familiar with this area, recommended texts are:

Schmitt, David A. International Programming for Microsoft Windows. Redmond WA: Microsoft Press, 2000.

Kano, Nadine. Developing International Software for Windows 95 and Windows NT. Redmond WA: Microsoft Press, 1995.  [Out of print]

There are two different ways you can proceed to internationalize GenDS:

1. Localized Resource DLLs, Selected at Install

Extract all of the localizable resources into a locale-specific resource-only DLL, localize that DLL for each desired locale, modify GenDS to take its resources from the localized DLL, and install the appropriate DLL at installation time.  This process is covered reasonably well by Schmitt in his book, and Dosadi can offer support for the specifics of GenDS.

2. Localized Resource DLLs, Selected at Run-time

You can take technique (1) above and make it more dynamic, by installing all of your localized DLLs, and selecting the appropriate one when your DS is loaded.  David Schmitt also covers this technique in his book.  This is appropriate if you want to offer excellent support for Microsoft’s newer platforms, which are moving toward a more multilingual model with dynamic switching of language and locale.



[1] I’m ignoring those extreme hackers who built external drives and feeders for handscanners.